import os
import logging
from dataclasses import dataclass
from typing import List

@dataclass
class FileInfo:
    name: str
    path: str
    size_gb: float
    type: str  # 'file' or 'directory'

def bytes_to_gb(size_bytes: int) -> float:
    return round(size_bytes / (1024**3), 2)

def scan_directory(path: str) -> List[FileInfo]:
    result = []
    
    def _scan(current_path):
        with os.scandir(current_path) as entries:
            for entry in entries:
                hook_processing(entry.path)
                
                if entry.is_file():
                    size = entry.stat().st_size
                    result.append(FileInfo(
                        name=entry.name,
                        path=entry.path,
                        size_gb=bytes_to_gb(size),
                        type='file'
                    ))
                elif entry.is_dir():
                    dir_size = 0
                    try:
                        for root, _, files in os.walk(entry.path):
                            for f in files:
                                fp = os.path.join(root, f)
                                try:
                                    if os.path.exists(fp):
                                        dir_size += os.path.getsize(fp)
                                except FileNotFoundError:
                                    hook_processing(fp)
                                    continue
                                except PermissionError:
                                    hook_processing(fp)
                                    pass
                    except PermissionError as e:
                        hook_processing(entry.path)
                        logging.error(f"无法访问目录 {entry.path}: {str(e)}")
                    except Exception as e:
                        hook_processing(entry.path)
                        logging.error(f"遍历目录 {entry.path} 时发生未知错误: {str(e)}")
                    
                    result.append(FileInfo(
                        name=entry.name,
                        path=entry.path,
                        size_gb=bytes_to_gb(dir_size),
                        type='directory'
                    ))
    
    _scan(path)
    return sorted(result, key=lambda x: x.size_gb, reverse=True)

from typing import Callable

# 定义观察者回调函数类型
HookCallback = Callable[[str], None]

# 全局状态观察器
_hook_observer: HookCallback = lambda _: None

def hook_processing(file_path: str):
    try:
        # 调用观察者回调
        _hook_observer(file_path)
    except Exception as e:
        logging.error(f"处理文件 {file_path} 时发生异常: {str(e)}")

# 注册观察者方法
def register_hook_observer(callback: HookCallback):
    global _hook_observer
    _hook_observer = callback

if __name__ == '__main__':
    target_path = 'D:\\'
    items = scan_directory(target_path)
    
    print(f'扫描结果（{target_path}）:')
    for item in items:
        print(f'{item.name} ({item.type}) - {item.size_gb} GB')